package br.ufpe.cin.mac.middleware.connectors.concrete;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import br.ufpe.cin.mac.middleware.connectors.ConcreteConnector;
import br.ufpe.cin.mac.util.ConnectionPackage;
import br.ufpe.cin.mac.util.Constants;
import br.ufpe.cin.mac.util.Message;


/**
 * Class TcpServer
 * 
 * @author Osmany
 * @author Rafael Roque
 *
 */
public class TcpServer extends ConcreteConnector implements TcpServerMBean {

	// private final int PORT = 1096;

	private ServerSocket serverSocket;

	private Map<String, ConnectionPackage> connections;

	String type;

	public TcpServer() {
		super(TcpServer.class.getCanonicalName());
		this.connections = Collections
				.synchronizedMap(new HashMap<String, ConnectionPackage>());
	}

	public void connect() {
		try {
			serverSocket = new ServerSocket(Constants.TCP_PORT);
		} catch (Exception e) {
			e.printStackTrace();
		}
		while (serverSocket.isBound()) {
			try {
				final Socket socket = serverSocket.accept();
				new Thread() {
					public void run() {
						receive(socket);
					}
				}.start();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public void disconnect(Socket socket) throws Exception {
	}


	public void invC(Message msg) {

		this.invS.put(msg);

		sendNotification(msg.hashCode(), "invS");
	}

	public Message invS(int hashMsg) {
		return (Message) this.invS.get(hashMsg);
	}

	public Message terC(int hashMsg) {
		try {
			final Message msg = (Message) this.terC.get(hashMsg);
			new Thread() {
				public void run() {
					send(msg);
				}
			}.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public void terS(Message msg) {

		this.terC.put(msg);

		sendNotification(msg.hashCode(), "terC");
	}

	/* EXPERIMENTAL */

	private void receive(Socket socket) {
		try {
			ObjectInputStream in = new ObjectInputStream(socket
					.getInputStream());
			Message msg = (Message) in.readObject();
			ConnectionPackage pack = new ConnectionPackage(socket);
			pack.setIn(in);
			this.connections.put(msg.getSender(), pack);
			this.invC(msg);

			while (socket.isConnected()) {
				msg = (Message) in.readObject();
				this.invC(msg);
			}
		} catch (Exception e) {
			System.err.println("Conexao Finalizada");
		}
	}

	private void send(Message msg) {
		String client = msg.getReceiver();
		ConnectionPackage pack = connections.get(client);
		synchronized (pack) {
			ObjectOutputStream out = pack.getOut();
			connections.put(client, pack);
			try {
				out.writeObject(msg);
				out.flush();
				System.out.println("####");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}


	@Override
	protected void msgManager(Message msg) {

	}

	@Override
	public void setHost(String host) {
		// TODO Auto-generated method stub
		
	}

}
